package com.gitee.wsl.mathematics.matrix.mat4

import com.gitee.wsl.ext.array.FloatArray
import com.gitee.wsl.io.dataproxy.DataProxy
import com.gitee.wsl.io.dataproxy.asProxy
import com.gitee.wsl.mathematics.matrix.M
import com.gitee.wsl.mathematics.matrix.MatCopyInitializer
import com.gitee.wsl.mathematics.matrix.MatInitializer
import com.gitee.wsl.mathematics.matrix.N
import com.gitee.wsl.mathematics.matrix.mat2.MutableMat2f
import com.gitee.wsl.mathematics.matrix.mat2.MutableMatrix2
import com.gitee.wsl.mathematics.matrix.mat3.MutableMat3f
import com.gitee.wsl.mathematics.matrix.mat3.MutableMatrix3
import com.gitee.wsl.mathematics.vector.vec3.MutableVec3f
import com.gitee.wsl.mathematics.vector.vec4.MutableVec4f
import com.gitee.wsl.mathematics.vector.vec4.MutableVector4
import com.gitee.wsl.mathematics.vector.vec4.Vec4f

open class MutableMat4f(m00: Float=0.0f, m01: Float=0.0f, m02: Float=0.0f, m03: Float=0.0f,
                        m10: Float=0.0f, m11: Float=0.0f, m12: Float=0.0f, m13: Float=0.0f,
                        m20: Float=0.0f, m21: Float=0.0f, m22: Float=0.0f, m23: Float=0.0f,
                        m30: Float=0.0f, m31: Float=0.0f, m32: Float=0.0f, m33: Float=0.0f,
                        override val proxy: DataProxy<Float> =
                            FloatArray(
                          m00, m01, m02, m03,
                          m10, m11, m12, m13,
                          m20, m21, m22, m23,
                          m30, m31, m32, m33
                      ).asProxy())
    :Mat4f(proxy = proxy),MutableMatrix4F<Mat4f, Vec4f> {
    constructor(other: Matrix4F<*, *>):this(
        other.m00, other.m01, other.m02, other.m03,
        other.m10, other.m11, other.m12, other.m13,
        other.m20, other.m21, other.m22, other.m23,
        other.m30, other.m31, other.m32, other.m33
    )
    constructor(initializer: MatInitializer<Float>):this(
        initializer(0,0),initializer(0,1),initializer(0,2),initializer(0,3),
        initializer(1,0),initializer(1,1),initializer(1,2),initializer(1,3),
        initializer(2,0),initializer(2,1),initializer(2,2),initializer(2,3),
        initializer(3,0),initializer(3,1),initializer(3,2),initializer(3,3)
    )

    override val self
        get() = this

    override val m by lazy{listOf(M[0], M[1],M[2], M[3])}

    override val n by lazy {listOf(N[0], N[1],N[2], N[3])}

    //override fun createVec(indexRage:IntRange) = createVec(indexRage.toList())

    override fun createVec(indexes: List<Int>) = MutableVec4f(proxy = proxy.asProxy(indexes))

    override fun createVec3(x: Float, y: Float, z: Float) = MutableVec3f(x, y, z)

    override fun createVec4(block: (MutableVector4<Float, *>) -> Unit): MutableVec4f {
        val ret = MutableVec4f()
        block(ret)
        return ret
    }

    override fun createMat2(block: (MutableMatrix2<Float, *, *>) -> Unit): MutableMat2f {
        val ret = MutableMat2f()
        block(ret)
        return ret
    }

    override fun createMat3(block: (MutableMatrix3<Float, *, *>) -> Unit): MutableMat3f {
        val ret = MutableMat3f()
        block(ret)
        return ret
    }

    override fun create(
        m00: Float, m01: Float, m02: Float, m03: Float,
        m10: Float, m11: Float, m12: Float, m13: Float,
        m20: Float, m21: Float, m22: Float, m23: Float,
        m30: Float, m31: Float, m32: Float, m33: Float,
    ) = MutableMat4f(
        m00, m01, m02, m03,
        m10, m11, m12, m13,
        m20, m21, m22, m23,
        m30, m31, m32, m33
    )

    override fun toMutable() = this

    override operator fun M.get(row: Int) = createVec(rowIndexes(row))

    override operator fun N.get(col: Int) = createVec(colIndexes(col))

    override fun copy(block: MatCopyInitializer<Float>) = MutableMat4f{ i, j->
        this[i,j].block(i,j)
    }

    companion object{

        val IDENTITY  = identity()

        fun identity()= MutableMat4f(
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
        )
    }
}